package com.example.matchingengine.service.model;

import com.example.matchingengine.config.TopicConfig;
import com.example.matchingengine.model.Order;
import com.example.matchingengine.model.Order.OrderSide;
import com.example.matchingengine.model.Order.OrderStatus;
import com.example.matchingengine.service.PersistenceService;
import com.example.matchingengine.service.event.TradeEvent;
import com.example.matchingengine.service.strategy.MatchingStrategy;
import com.example.matchingengine.service.strategy.PrototypeStrategyFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.micrometer.core.instrument.Counter;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 订单簿
 * 包含买盘和卖盘，实现订单撮合逻辑
 */
@Slf4j
public class OrderBook {
    private final String symbol;

    // 买盘 - 价格优先（降序），同价格时间优先
    private final TreeMap<BigDecimal, LinkedList<Order>> buyOrders;

    // 卖盘 - 价格优先（升序），同价格时间优先
    private final TreeMap<BigDecimal, LinkedList<Order>> sellOrders;

    // 订单ID到订单的映射，用于快速查找订单
    private final Map<String, Order> orderMap = new HashMap<>();

    // 依赖注入的服务
    private RocketMQTemplate rocketMQTemplate;
    private Counter tradeCounter;
    private ObjectMapper objectMapper;
    private PersistenceService persistenceService;
    private TopicConfig topicConfig;

    public OrderBook(String symbol) {
        this.symbol = symbol;
        this.buyOrders = new TreeMap<>(Comparator.reverseOrder());
        this.sellOrders = new TreeMap<>();
    }

    /**
     * 设置依赖服务
     */
    public void setDependencies(RocketMQTemplate rocketMQTemplate, Counter tradeCounter,
                               ObjectMapper objectMapper, PersistenceService persistenceService,
                               TopicConfig topicConfig) {
        this.rocketMQTemplate = rocketMQTemplate;
        this.tradeCounter = tradeCounter;
        this.objectMapper = objectMapper;
        this.persistenceService = persistenceService;
        this.topicConfig = topicConfig;
    }

    /**
     * 撮合订单
     */
    public void matchOrder(Order order) {
        // 添加到订单映射表，用于快速查找
        orderMap.put(order.getId(), order);
        
        // 检查订单状态，如果是取消状态，则不进行撮合 
        if (order.getStatus() == OrderStatus.CANCELED) { 
            log.info("订单已取消，不进行撮合: {}", order.getId()); 
            return; 
        } 

        // 使用原型策略模式进行订单撮合（支持策略对象复用）
        try {
            MatchingStrategy strategy = PrototypeStrategyFactory.getStrategy(order);
            strategy.match(order, this);
        } catch (Exception e) {
            log.error("订单撮合失败: {}, 错误: {}", order.getId(), e.getMessage(), e);
            // 撮合失败时，将订单状态设置为拒绝
            order.setStatus(OrderStatus.REJECTED);
            order.setUpdateTime(LocalDateTime.now());
            sendOrderStatusUpdate(order);
        }
    }

    /**
     * 添加订单到订单簿（不进行撮合）
     */
    public void addOrder(Order order) {
        orderMap.put(order.getId(), order);
        if (order.getSide() == OrderSide.BUY) {
            LinkedList<Order> ordersAtPrice = buyOrders.computeIfAbsent(order.getPrice(), k -> new LinkedList<>());
            ordersAtPrice.addLast(order);
        } else {
            LinkedList<Order> ordersAtPrice = sellOrders.computeIfAbsent(order.getPrice(), k -> new LinkedList<>());
            ordersAtPrice.addLast(order);
        }
    }

    /**
     * 更新订单
     */
    public void updateOrder(Order order) {
        Order existingOrder = orderMap.get(order.getId());
        if (existingOrder != null) {
            existingOrder.setStatus(order.getStatus());
            existingOrder.setFilledQuantity(order.getFilledQuantity());
            existingOrder.setUpdateTime(order.getUpdateTime());

            if (order.getStatus() == OrderStatus.FILLED || 
                order.getStatus() == OrderStatus.CANCELED || 
                order.getStatus() == OrderStatus.PARTIALLY_FILLED_CANCELED) {
                removeOrder(order);
            }
        }
    }

    /**
     * 移除订单
     */
    public void removeOrder(Order order) {
        orderMap.remove(order.getId());
        TreeMap<BigDecimal, LinkedList<Order>> orders =
                order.getSide() == OrderSide.BUY ? buyOrders : sellOrders;

        LinkedList<Order> ordersAtPrice = orders.get(order.getPrice());
        if (ordersAtPrice != null) {
            ordersAtPrice.removeIf(o -> o.getId().equals(order.getId()));
            if (ordersAtPrice.isEmpty()) {
                orders.remove(order.getPrice());
            }
        }
    }

    /**
     * 查找并取消订单
     */
    public Order findAndCancelOrder(String orderId) {
        Order order = orderMap.get(orderId);
        if (order != null) {
            order.setStatus(OrderStatus.CANCELED);
            order.setUpdateTime(LocalDateTime.now());
            removeOrder(order);
            return order;
        }
        return null;
    }

    /**
     * 创建订单簿快照
     */
    public OrderBookSnapshot createSnapshot() {
        OrderBookSnapshot snapshot = new OrderBookSnapshot();
        snapshot.setSymbol(this.symbol);

        for (Map.Entry<BigDecimal, LinkedList<Order>> entry : buyOrders.entrySet()) {
            for (Order order : entry.getValue()) {
                snapshot.getBuyOrders().add(OrderSnapshot.fromOrder(order));
            }
        }

        for (Map.Entry<BigDecimal, LinkedList<Order>> entry : sellOrders.entrySet()) {
            for (Order order : entry.getValue()) {
                snapshot.getSellOrders().add(OrderSnapshot.fromOrder(order));
            }
        }

        return snapshot;
    }

    /**
     * 从快照恢复订单簿
     */
    public void restoreFromSnapshot(OrderBookSnapshot snapshot) {
        for (OrderSnapshot orderSnapshot : snapshot.getBuyOrders()) {
            Order order = orderSnapshot.toOrder();
            LinkedList<Order> ordersAtPrice = buyOrders.computeIfAbsent(order.getPrice(), k -> new LinkedList<>());
            ordersAtPrice.addLast(order);
            orderMap.put(order.getId(), order);
        }

        for (OrderSnapshot orderSnapshot : snapshot.getSellOrders()) {
            Order order = orderSnapshot.toOrder();
            LinkedList<Order> ordersAtPrice = sellOrders.computeIfAbsent(order.getPrice(), k -> new LinkedList<>());
            ordersAtPrice.addLast(order);
            orderMap.put(order.getId(), order);
        }

        log.info("订单簿恢复完成，交易对: {}，买单数量: {}，卖单数量: {}，订单映射表大小: {}",
                symbol, buyOrders.size(), sellOrders.size(), orderMap.size());
    }


    
    /**
     * 检查订单是否可以完全成交
     */
    public boolean canFillCompletely(Order order) {
        BigDecimal availableQuantity = BigDecimal.ZERO;
        
        if (order.getSide() == OrderSide.BUY) {
            // 买单检查卖盘可用数量
            for (Map.Entry<BigDecimal, LinkedList<Order>> entry : sellOrders.entrySet()) {
                BigDecimal sellPrice = entry.getKey();
                // 只考虑价格不高于买单价格的卖单
                if (sellPrice.compareTo(order.getPrice()) <= 0) {
                    for (Order sellOrder : entry.getValue()) {
                        BigDecimal remainingQty = sellOrder.getQuantity().subtract(sellOrder.getFilledQuantity());
                        availableQuantity = availableQuantity.add(remainingQty);
                        
                        // 如果可用数量已经足够，返回true
                        if (availableQuantity.compareTo(order.getQuantity()) >= 0) {
                            return true;
                        }
                    }
                } else {
                    break; // 价格太高，退出循环
                }
            }
        } else {
            // 卖单检查买盘可用数量
            for (Map.Entry<BigDecimal, LinkedList<Order>> entry : buyOrders.entrySet()) {
                BigDecimal buyPrice = entry.getKey();
                // 只考虑价格不低于卖单价格的买单
                if (buyPrice.compareTo(order.getPrice()) >= 0) {
                    for (Order buyOrder : entry.getValue()) {
                        BigDecimal remainingQty = buyOrder.getQuantity().subtract(buyOrder.getFilledQuantity());
                        availableQuantity = availableQuantity.add(remainingQty);
                        
                        // 如果可用数量已经足够，返回true
                        if (availableQuantity.compareTo(order.getQuantity()) >= 0) {
                            return true;
                        }
                    }
                } else {
                    break; // 价格太低，退出循环
                }
            }
        }
        
        return false;
    }
    
    /**
     * 处理未成交部分（针对IOC和FOK订单）
     */
    public void handleUnfilledPortion(Order order) {
        boolean isFullyFilled = order.getFilledQuantity().compareTo(order.getQuantity()) >= 0;
        
        if (!isFullyFilled) {
            if (order.getTimeInForce() == Order.TimeInForce.IOC) {
                // IOC订单未成交部分取消，状态为PARTIALLY_FILLED_CANCELED
                if (order.getFilledQuantity().compareTo(BigDecimal.ZERO) > 0) {
                    order.setStatus(OrderStatus.PARTIALLY_FILLED_CANCELED);
                    log.info("IOC订单部分成交后取消: {}, 成交数量: {}", 
                            order.getId(), order.getFilledQuantity());
                } else {
                    order.setStatus(OrderStatus.REJECTED);
                    log.info("IOC订单完全未成交，已拒绝: {}", order.getId());
                }
                order.setUpdateTime(LocalDateTime.now());
                // IOC订单不加入订单簿
            } else if (order.getTimeInForce() == Order.TimeInForce.FOK) {
                // FOK订单在这里不会被调用，因为在前面已经检查过了
                // 但为了保险起见，还是加上这个处理
                order.setStatus(OrderStatus.REJECTED);
                order.setUpdateTime(LocalDateTime.now());
                log.warn("FOK订单未完全成交，已拒绝: {}", order.getId());
            } else {
                // GTC订单加入订单簿，状态为PARTIALLY_FILLED
                order.setStatus(OrderStatus.PARTIALLY_FILLED);
                if (order.getSide() == OrderSide.BUY) {
                    LinkedList<Order> ordersAtPrice = buyOrders.computeIfAbsent(order.getPrice(), k -> new LinkedList<>());
                    ordersAtPrice.addLast(order);
                } else {
                    LinkedList<Order> ordersAtPrice = sellOrders.computeIfAbsent(order.getPrice(), k -> new LinkedList<>());
                    ordersAtPrice.addLast(order);
                }
                log.info("GTC订单部分成交后加入订单簿: {}, 成交数量: {}", 
                        order.getId(), order.getFilledQuantity());
            }
        }
    }


    /**
     * 写入WAL日志
     */
    private void writeWalLog(String operation, String data) {
        if (persistenceService != null && persistenceService.isWalEnabled()) {
            try {
                persistenceService.writeWalLog(operation, data);
            } catch (Exception e) {
                log.error("写入WAL日志失败: {}", e.getMessage(), e);
            }
        }
    }

    // 发送消息的辅助方法
    public void sendOrderStatusUpdate(Order order) {
        if (rocketMQTemplate != null && topicConfig != null) {
            try {
                String orderStatusTopic = topicConfig.getOrderStatusTopic(this.symbol);
                rocketMQTemplate.convertAndSend(orderStatusTopic, order);
                log.info("订单状态更新已发送到topic {}: {}, 状态: {}", orderStatusTopic, order.getId(), order.getStatus());
                
                // 记录到WAL日志
                if (objectMapper != null) {
                    try {
                        String orderJson = objectMapper.writeValueAsString(order);
                        writeWalLog("UPDATE_ORDER", orderJson);
                    } catch (Exception e) {
                        log.error("记录订单状态更新到WAL日志失败: {}", e.getMessage(), e);
                    }
                }
            } catch (Exception e) {
                log.error("发送订单状态更新失败: {}", e.getMessage(), e);
            }
        }
    }

    public void sendTradeEvent(TradeEvent tradeEvent) {
        if (rocketMQTemplate != null && topicConfig != null) {
            try {
                String tradeTopic = topicConfig.getTradeTopic(this.symbol);
                rocketMQTemplate.convertAndSend(tradeTopic, tradeEvent);
                log.info("成交事件已发送到topic {}: {}", tradeTopic, tradeEvent);
                
                // 记录到WAL日志
                if (objectMapper != null) {
                    try {
                        String tradeJson = objectMapper.writeValueAsString(tradeEvent);
                        writeWalLog("TRADE", tradeJson);
                    } catch (Exception e) {
                        log.error("记录成交事件到WAL日志失败: {}", e.getMessage(), e);
                    }
                }
            } catch (Exception e) {
                log.error("发送成交事件失败: {}", e.getMessage(), e);
            }
        }
    }

    // Getters for access from MatchingEngineService
    public TreeMap<BigDecimal, LinkedList<Order>> getBuyOrders() {
        return buyOrders;
    }

    public TreeMap<BigDecimal, LinkedList<Order>> getSellOrders() {
        return sellOrders;
    }

    public Map<String, Order> getOrderMap() {
        return orderMap;
    }

    public String getSymbol() {
        return symbol;
    }
    
    /**
     * 增加成交计数
     */
    public void incrementTradeCounter() {
        if (tradeCounter != null) {
            tradeCounter.increment();
        }
    }
}